//
// Created by wangwanlong on 2024/11/4.
//

#ifndef MKAHYPAR_REFINER_BASE_H
#define MKAHYPAR_REFINER_BASE_H
#include "mkahypar/utils/typedef.h"
namespace mkahypar{
  //回滚
  struct RollbackInfo {
    HypernodeID hn;
    PartitionID from_part;
    PartitionID to_part;
  };

  class RefinerBase{
  public:
    RefinerBase(const RefinerBase&) = delete;
    RefinerBase& operator= (const RefinerBase&) = delete;
    RefinerBase(RefinerBase&&) = delete;
    RefinerBase& operator= (RefinerBase&&) = delete;
    ~RefinerBase() = default;

    RefinerBase(Hypergraph& hypergraph,TargetGraph& topo):
    _hg(hypergraph),_topo(topo){
      _performed_moves.reserve(hypergraph.initialNumNodes());
    }



    //不考虑from和to非法的情况
    void changeNodePart(const HypernodeID hn, const PartitionID from, const PartitionID to){
      if(from == to)
        ERROREXIT("error!");
      //资源量更正
      _topo._fpga[from]._used_res -= _hg.hypernode(hn).weight();
      _topo._fpga[to]._used_res += _hg.hypernode(hn).weight();
      //更改节点分区
      _hg.hypernode(hn).part_id = to;
      for (const HyperedgeID &he: _hg.incidentEdges(hn)){
        HypernodeID source = _hg.hyperedge(he).source();
        HyperedgeWeight he_weight = _hg.edgeWeight(he);
        //更新pin_in_part
        bool no_pins_left_in_source_part = _hg.decrementPinCountInPart(he, from);
        bool only_one_pin_in_to_part = _hg.incrementPinCountInPart(he, to);
        //更新target_part_route_count
        if(hn != source) {
          _hg.decrementRouteCountInPart(he, from, hn);
          _hg.incrementRouteCountInPart(he, to, hn);
        }
        //更新互联量
        if (no_pins_left_in_source_part && !only_one_pin_in_to_part) {
          if (_hg.pinCountInPart(he, to) == _hg.edgeSize(he)) {
            //eg1.边界边 -> 内部边，不再占用from和to的互联量
            _topo._fpga[from]._used_line -= he_weight;
            _topo._fpga[to]._used_line -= he_weight;
            for (const HypernodeID &pin: _hg.pins(he)) {
              --_hg.hypernode(pin).num_incident_cut_hes;
            }
          }
          else{
            //eg2. 边界边-> 边界边，只是不再占用from的互联量
            _topo._fpga[from]._used_line -= he_weight;
          }
        } else if (!no_pins_left_in_source_part && only_one_pin_in_to_part) {
          if(_hg.pinCountInPart(he, from) + 1 == _hg.edgeSize(he)) {
            //eg3.内部边->边界边，这个时候会占用from和to的互联量
            _topo._fpga[from]._used_line += he_weight;
            _topo._fpga[to]._used_line += he_weight;
            for (const HypernodeID &pin: _hg.pins(he)) {
              ++_hg.hypernode(pin).num_incident_cut_hes;
            }
          }
          else{
            //eg4. 边界边-> 边界边，新增to的互联量
            _topo._fpga[to]._used_line += he_weight;
          }
        }
        else if(no_pins_left_in_source_part && only_one_pin_in_to_part){
          //eg5. 边界边-> 边界边， 减少from的互联量，增加to的互联量
          _topo._fpga[from]._used_line -= he_weight;
          _topo._fpga[to]._used_line += he_weight;

        }
        //对于！no_pins_left_in_source_part && ！only_one_pin_in_to_part这种情况，不会改变互联量
      }
    }


    Hypergraph & _hg;
    TargetGraph & _topo;

    std::vector<RollbackInfo> _performed_moves;//最优解回滚

  };
}
#endif //MKAHYPAR_REFINER_BASE_H
